﻿// SmallUtilz.cpp: implementation of the CSmallUtilz4iTrans class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "iTrans.h"
#include "SmallUtilz.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CSmallUtilz4iTrans::CSmallUtilz4iTrans()
{

}

CSmallUtilz4iTrans::~CSmallUtilz4iTrans()
{

}

bool CSmallUtilz4iTrans::IsFileorfolder(LPCTSTR szPathName, bool bFolder)
{
	DWORD dwRet;
	dwRet = GetFileAttributes(szPathName);
	if(dwRet==0xffffffff) return false;					// 오류 발생
	
	bool ret = !(dwRet & FILE_ATTRIBUTE_DIRECTORY);
	return (bFolder)?(!ret):ret;
}

UINT CSmallUtilz4iTrans::GetFileSize(LPCTSTR sPathName)
{
	HANDLE	hFile;
	UINT		nSize;
	hFile = ::CreateFile(sPathName, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
		FILE_FLAG_SEQUENTIAL_SCAN, NULL);
	if(hFile==INVALID_HANDLE_VALUE) return -1;
	nSize = ::GetFileSize(hFile, NULL);
	CloseHandle(hFile);
	return nSize;
}

static int multiply4Time[] = {
	36000000,	3600000,
	600000,		60000,
	10000,		1000,
	100,		10,		1
};

static signed char step4Time[] = {
	0,		1,
	3,		4,
	6,		7,
	9,		10,		11
};

int CSmallUtilz4iTrans::tcTime2Int(TCHAR *tc, bool splitExists)
{
	int ret = 0;
	for (int i=0; i<9; i++) {
		ret += (tc[(splitExists)?(step4Time[i]):(i)]-_TCHAR('0'))*multiply4Time[i];
	}

	return ret;
}

int CSmallUtilz4iTrans::cTime2Int(char *c, bool splitExists)
{
	int ret = 0;
	for (int i=0; i<9; i++) {
		ret += (c[(splitExists)?(step4Time[i]):(i)]-('0'))*multiply4Time[i];
	}
	
	return ret;
}

void CSmallUtilz4iTrans::ms2HMSMS(int ms0, int &h, int &m, int &s, int &ms)
{
	if (ms0<0) ms0=0;
	
	s = ms0/1000;
	ms = ms0 % 1000;
	m = s / 60;
	s %= 60;
	h = m / 60;
	m %= 60;
	
	if (h>99) {
		h = 99;
		m = s = 59;
		ms = 999;
	}
}

bool CSmallUtilz4iTrans::CheckTempFolderInt(LPCTSTR tcFolder, BOOL bRecyclebin)
{
	// 확인하는 것
	// 1. 임시 폴더가 존재하고 쓰기 가능한 폴더인가
	// 2. 임시 폴더 이름의 길이가 231자 이상인가
	// 3. 임시 폴더 이름에 한글 등이 들어가는가
	
	if (!bIsFolderWritable(tcFolder, bRecyclebin)) return false;
	
	int len = _tcslen(tcFolder);
	if (len>230) return false;
	for (int i=0; i<len; i++) {
		if (tcFolder[i]<_TCHAR(' ') || tcFolder[i]>_TCHAR(127)) return false;
	}
	
	return true;
}

bool CSmallUtilz4iTrans::CheckTempFolder(CString &csTempFolder, BOOL bRecyclebin)
{
	// 1. 기존의 임시 폴더가 사용 가능한지 확인
	// 2. 사용 불가능하면 윈도우의 임시 폴더가 사용 가능한지 확인
	// 3. 그것도 아니면 윈도우+"\temp"가 사용 가능한지 확인
	// 4. 1-2-3 모두 실패면 실패 리턴
	// 5. 2-3의 경우 뒤에 "\iTrans" 붙임
	
	CString csT(csTempFolder);
	csT.TrimRight(_TCHAR('\\'));
	
	if (CheckTempFolderInt(csT, bRecyclebin)) return true;
	
	CString csTbase;
	csTbase = csGetWindowsTempPath();
	
	if (!CheckTempFolderInt(csTbase, bRecyclebin)) {
		csTbase = csGetWindowsPath()+_T("\\temp");
		_tmkdir(csTbase);
		if (!CheckTempFolderInt(csTbase, bRecyclebin)) {
			return false;
		}
	}
	
	csT = csTbase+_T("\\iTrans");
	_tmkdir(csT);
	if (bIsFolderWritable(csT, bRecyclebin)) {
		csTempFolder = csT+_TCHAR('\\');
		return true;
	}
	
	for (int i=0; i<1000; i++) {
		CString csTnum;
		csTnum.Format(_T("%s%03d"), static_cast<LPCTSTR>(csT), i);
		_tmkdir(csTnum);
		if (bIsFolderWritable(csTnum, bRecyclebin)) {
			csTempFolder = csTnum+_TCHAR('\\');
			return true;
		}
	}
	
	return false;
}

CString CSmallUtilz4iTrans::csGetWindowsTempPath()
{
	static BOOL bFirst=TRUE;
	static CString csRet;
	static TCHAR tcTemp[MAX_PATH];
	
	if (bFirst) {
		GetTempPath(MAX_PATH, tcTemp);
		csRet = tcTemp;
		csRet.TrimRight(_TCHAR('\\'));
		
		bFirst = FALSE;
	}
	
	return csRet;
}

CString CSmallUtilz4iTrans::csGetWindowsPath()
{
	static BOOL bFirst=TRUE;
	static CString csRet;
	static TCHAR tcTemp[MAX_PATH];
	
	if (bFirst) {
		GetWindowsDirectory(tcTemp, MAX_PATH);
		csRet = tcTemp;
		csRet.TrimRight(_TCHAR('\\'));
		
		bFirst = FALSE;
	}
	
	return csRet;
}

BOOL CSmallUtilz4iTrans::bIsFolderWritable(LPCTSTR tcFolder, BOOL bRecyclebin)
{
	if (!CSmallUtilz4iTrans::IsFileorfolder(tcFolder, true)) return FALSE;
	
	CString cs(tcFolder);
	cs.TrimRight(_TCHAR('\\'));
	cs += _T("\\tempfile.BLUEnLIVE.iTrans");

	FILE *f;
	if (_tfopen_s(&f, cs, _T("wb")) || !f) return FALSE;
	fclose(f);
	
	DeleteSomeFile(cs, bRecyclebin);
	
	return TRUE;
}

void CSmallUtilz4iTrans::DeleteSomeFile(LPCTSTR lpFilename, BOOL bRecyclebin)
{
	SHFILEOPSTRUCT op;
	ZeroMemory(&op, sizeof(SHFILEOPSTRUCT));

	int len = _tcslen(lpFilename);
	TCHAR *tc = new TCHAR[len+2];
	_tcscpy_s(tc, len+2, lpFilename);
	tc[len] = tc[len+1] = 0;

	op.wFunc = FO_DELETE;
	op.pFrom = tc;

	op.fFlags = FOF_SILENT |			// don't report progress
		FOF_NOERRORUI |				// don't report errors
		FOF_NOCONFIRMATION;			// don't confirm delete
		
	if (bRecyclebin)
		op.fFlags |= FOF_ALLOWUNDO;		// send to Recycle Bin
	else
		op.fFlags &= ~FOF_ALLOWUNDO;	// don't send to Recycle Bin

	SHFileOperation(&op);
	delete []tc;
}

void CSmallUtilz4iTrans::EnableDialgItem(HWND hWnd, int nID, BOOL bEnabled)
{
	EnableWindow(GetDlgItem(hWnd, nID), bEnabled);
}

bool CSmallUtilz4iTrans::getAppVersionNumber(CString &csVersion)
{
	TCHAR szFilename[MAX_PATH*4] = {0};
	csVersion = _T("1.0");
    if (GetModuleFileName(NULL, szFilename, MAX_PATH*4) == 0) {
        return false;
    }
	
	WORD vers[4];
	CString csInternalName;	// dummy

	getVersionNoAndInternalName(szFilename, vers, csInternalName);
	if (!vers[0] && !vers[1]) return false;

	csVersion.Format(_T("%u.%u"), vers[0], vers[1]);
	if ((vers[2]>=1) && (vers[2]<=26)) {
		csVersion.AppendFormat(_T("%c"), vers[2]+_TCHAR('a')-1);
	}

	if (vers[3]) {
		csVersion.AppendFormat(_T(" (build %u)"), vers[3]);
	}

	return true;
}

DWORD CSmallUtilz4iTrans::decibel2DWORD(double decibel) {
	bool negative = (decibel<0.0);
	if (negative) decibel = -decibel;

	DWORD ret = static_cast<DWORD>(decibel*1000000);
	ret <<= 1;

	if (negative) ret |= 1;

	return ret;
}
double CSmallUtilz4iTrans::DWORD2decibel(DWORD dw) {
	bool negative = (dw & 1);
	dw >>= 1;

	double ret = dw/1000000.0;
	if (negative) ret = -ret;

	return ret;
}

LPCTSTR CSmallUtilz4iTrans::getAppNameOnly(LPCTSTR lpApp)
{
	LPCTSTR lpAppName = lpApp+(_tcslen(lpApp));
	while (*lpAppName != _TCHAR('\\')) lpAppName--;
	return (lpAppName+1);
}


void CSmallUtilz4iTrans::getVersionNoAndInternalName(LPCTSTR lpFilename, WORD *vers, CString & csInternalname)
{
	ZeroMemory(vers, sizeof(WORD)*4);
	csInternalname = _T("");

	// allocate a block of memory for the version info
	DWORD dummy;
	DWORD dwSize = GetFileVersionInfoSize(lpFilename, &dummy);
	if (!dwSize) {
		return;
	}
	BYTE *data = new BYTE[dwSize];

	// load the version info
	if (!GetFileVersionInfo(lpFilename, NULL, dwSize, data)) {
		delete []data;
		return;
	}

	UINT uLen;
	VS_FIXEDFILEINFO *lpFfi;
	if (!VerQueryValue(data, _T("\\"), (LPVOID*)&lpFfi, &uLen)) {
		delete []data;
		return;
	}

	vers[0] = HIWORD(lpFfi->dwFileVersionMS);
	vers[1] = LOWORD(lpFfi->dwFileVersionMS);
	vers[2] = HIWORD(lpFfi->dwFileVersionLS);
	vers[3] = LOWORD(lpFfi->dwFileVersionLS);

	DWORD langD;
	BOOL retVal;    

	LPVOID retbuf=NULL;

	static TCHAR fileEntry[MAX_PATH];

	retVal = VerQueryValue(data, _T("\\VarFileInfo\\Translation"), &retbuf, &uLen);
	if (retVal && uLen==4) {
		memcpy(&langD, retbuf, 4);
		_stprintf_s(fileEntry, MAX_PATH, _T("\\StringFileInfo\\%02X%02X%02X%02X\\InternalName"),
			(langD & 0xff00)>>8,		langD & 0xff,
			(langD & 0xff000000)>>24,	(langD & 0xff0000)>>16);            
	} else {
		_stprintf_s(fileEntry, MAX_PATH,  _T("\\StringFileInfo\\%04X04B0\\InternalName"), 
		GetUserDefaultLangID());
	}

	if (VerQueryValue(data,	fileEntry, &retbuf, &uLen)) 
		csInternalname = (LPTSTR)retbuf;

	delete []data;
}


void CSmallUtilz4iTrans::tokenize2CSA(LPCTSTR lpStr, CStringArray & csa)
{
	CString cs(lpStr);
	csa.RemoveAll();
	cs.Trim();
	while (cs.GetLength()) {
		int pos = cs.Find(_TCHAR(' '));
		if (pos<0) {
			csa.Add(cs);
			break;
		}
		csa.Add(cs.Left(pos));
		cs.Delete(0, pos);
		cs.TrimLeft();
	}
}


int CSmallUtilz4iTrans::findinCSAi(CStringArray & csa, LPCTSTR lpStr)
{
	for (int i=0; i<csa.GetSize(); i++) {
		if (csa.GetAt(i).CompareNoCase(lpStr) == 0) return i;
	}
	return -1;
}


void CSmallUtilz4iTrans::makeBatchFileName(CString & csBatch, CString & csFolder, LPCTSTR lpTitle)
{
	static int count=0;
	csBatch = csFolder;
	csBatch.TrimRight(_TCHAR('\\'));
	csBatch.AppendFormat(_T("\\%03d_%s.cmd"), count++, lpTitle);
}
